package cn.tqfeiyang.springplus.framework.conversion;

import cn.tqfeiyang.springplus.framework.Constants;
import org.modelmapper.AbstractConverter;
import org.modelmapper.Converter;
import org.modelmapper.ModelMapper;
import org.modelmapper.convention.MatchingStrategies;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;

@Configuration
public class ModelMapperConfiguration {

    @Bean
    public ModelMapper modelMapper() {
        ModelMapper modelMapper = new ModelMapper();
        modelMapper.getConfiguration().setFullTypeMatchingRequired(true)
                .setMatchingStrategy(MatchingStrategies.STRICT);
        modelMapper.addConverter(dateToStringConverter);
        modelMapper.addConverter(localDateToStringConverter);
        modelMapper.addConverter(localDateTimeToStringConverter);
        modelMapper.addConverter(stringToLocalDateConverter);
        modelMapper.addConverter(stringToLocalDateTimeConverter);
        modelMapper.addConverter(dateToLocalDateTimeConverter);
        modelMapper.addConverter(longToStringConverter);
        return modelMapper;
    }

    Converter<Date, String> dateToStringConverter = new AbstractConverter<Date, String>() {
        @Override
        protected String convert(Date date) {
            SimpleDateFormat simpleDateFormat =
                    new SimpleDateFormat(Constants.DATETIME_FORMAT);
            return date == null ? null : simpleDateFormat.format(date);
        }
    };

    Converter<LocalDate, String> localDateToStringConverter = new AbstractConverter<LocalDate, String>() {
        @Override
        protected String convert(LocalDate localDate) {
            DateTimeFormatter format = DateTimeFormatter.ofPattern(Constants.DATE_FORMAT);
            return localDate == null ? null : localDate.format(format);
        }
    };

    Converter<LocalDateTime, String> localDateTimeToStringConverter = new AbstractConverter<LocalDateTime, String>() {
        @Override
        protected String convert(LocalDateTime localDateTime) {
            DateTimeFormatter format = DateTimeFormatter.ofPattern(Constants.DATETIME_FORMAT);
            return localDateTime == null ? null : localDateTime.format(format);
        }
    };

    Converter<String, LocalDate> stringToLocalDateConverter = new AbstractConverter<String, LocalDate>() {
        @Override
        protected LocalDate convert(String source) {
            DateTimeFormatter format = DateTimeFormatter.ofPattern(Constants.DATE_FORMAT);
            LocalDate localDate = LocalDate.parse(source, format);
            return localDate;
        }
    };

    Converter<String, LocalDateTime> stringToLocalDateTimeConverter = new AbstractConverter<String, LocalDateTime>() {
        @Override
        protected LocalDateTime convert(String source) {
            DateTimeFormatter format = DateTimeFormatter.ofPattern(Constants.DATETIME_FORMAT);
            LocalDateTime localDateTime = LocalDateTime.parse(source, format);
            return localDateTime;
        }
    };

    Converter<Date, LocalDateTime> dateToLocalDateTimeConverter = new AbstractConverter<Date, LocalDateTime>() {
        @Override
        protected LocalDateTime convert(Date source) {
            return source.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        }
    };

    Converter<Long, String> longToStringConverter = new AbstractConverter<Long, String>() {
        @Override
        protected String convert(Long number) {
            return number == null ? null : number.toString();
        }
    };
}
